package com.jsu.forum.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jsu.client.UserClient;
import com.jsu.forum.mapper.CommentMapper;
import com.jsu.forum.mapper.LikesCountMapper;
import com.jsu.forum.mapper.PassageMapper;
import com.jsu.forum.service.CommentService;
import com.jsu.user.feign.UserServerClient;
import lombok.extern.slf4j.Slf4j;
import org.example.model.common.dtos.ResponseResult;
import org.example.model.common.enums.RedisCodeEnum;
import org.example.model.common.enums.WebHttpCodeEnum;
import org.example.model.forum.dto.*;
import org.example.model.forum.enums.PassageEnum;
import org.example.model.forum.pojo.LikesCount;
import org.example.model.forum.pojo.PassageComment;
import org.example.model.user.dto.UserDto;
import org.example.model.user.pojo.User;
import org.example.utils.common.IdsUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.*;

@Service
@Slf4j
@Transactional
public class CommentServiceImpl extends ServiceImpl<CommentMapper, PassageComment>implements CommentService {

    @Autowired
    private StringRedisTemplate redisCache;
    private ObjectMapper mapper = new ObjectMapper();
    @Autowired
    private LikesCountMapper likesCountMapper;
    @Autowired
    private HttpServletRequest request;
    @Autowired(required = false)
    private UserServerClient userClient;
    @Autowired
    private PassageMapper passageMapper;
    @Autowired
    private PassageServiceImpl passageService;

    /**
     * 发布评论
     * @param comment
     * @return
     */
    @Override
    public ResponseResult publishComment(PassageComment comment) {
        int commentId = Integer.parseInt(IdsUtils.creatCode());
        comment.setPkId(commentId);
        //存到redis中
        String key = RedisCodeEnum.PASSAGE_COMMENT.getMsg()+comment.getPkId();
        String json = null;
        try {
            json = mapper.writeValueAsString(comment);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        redisCache.opsForValue().set(key,json);
        //存到数据中
        int count = getBaseMapper().insert(comment);
        //对应文章评论数加一
        int count2 = passageMapper.addComment(comment.getPassageId());
        if(count2<=0){
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"更新评论数失败");
        }
        //在redis中更新评论数
        String key2 = RedisCodeEnum.FORUM_PASSAGE.getMsg()+comment.getPassageId();
        redisCache.opsForValue().getOperations().delete(key2);
        ForumDto forumDto = passageService.convertPassageToForumFto(passageMapper.selectById(comment.getPassageId()));
        String s = null;
        try {
            s = mapper.writeValueAsString(forumDto);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        redisCache.opsForValue().set(key2,s);

        if (count<=0) {
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"发布评论失败");
        }
        return ResponseResult.okResult(200,"发布成功");
    }

    /**
     * 删除评论
     * @param id
     * @return
     */
    @Override
    public ResponseResult deleteCommnet(Integer id) {
        //删除redis中的记录
        String key = RedisCodeEnum.PASSAGE_COMMENT.getMsg()+id;
        redisCache.opsForValue().getOperations().delete(key);
        //删除数据库中的记录
        int count = getBaseMapper().deleteById(id);
        if (count<=0) {
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"删除评论失败");
        }
        //更新评论数
        //对应文章评论数加一
        int count2 = passageMapper.reduceComment(id);
        if(count2<=0){
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"更新评论数失败");
        }
        //在redis中更新评论数
        String key2 = RedisCodeEnum.FORUM_PASSAGE.getMsg()+id;
        redisCache.opsForValue().getOperations().delete(key2);
        ForumDto forumDto = passageService.convertPassageToForumFto(passageMapper.selectById(id));
        String s = null;
        try {
            s = mapper.writeValueAsString(forumDto);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        redisCache.opsForValue().set(key2,s);
        return ResponseResult.okResult(200,"删除成功");
    }

    /**
     * 取消点赞评论
     * @param likeCountDto
     * @return
     */
    @Override
    public ResponseResult unlikesComment(LikeCountDto likeCountDto) {
        LikesCount likesCount = likesCountMapper.selectByCommentIdAndUserId(likeCountDto.getCommentId(),likeCountDto.getUseId());
        if(likesCount==null)
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"取消点赞失败");
        int count = likesCountMapper.deleteByCommentIdAndUserId(likeCountDto.getCommentId(),likeCountDto.getUseId());
        if(count<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"没有点赞记录");
        String key = RedisCodeEnum.PASSAGE_COMMENT_LIKE.getMsg()+likesCount.getPkId();
        redisCache.opsForValue().getOperations().delete(key);
        //更新评论的点赞数
        PassageComment passageComment = getBaseMapper().selectById(likesCount.getCommentId());
        passageComment.setLikesCount(passageComment.getLikesCount()-1);
        int count2 = getBaseMapper().updateById(passageComment);
        if(count2<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"更新评论点赞数失败");
        //更新redis中的点赞数
        String key2 = RedisCodeEnum.PASSAGE_COMMENT.getMsg()+likesCount.getCommentId();
        redisCache.opsForValue().getOperations().delete(key2);
        PassageComment passageComment2 = getBaseMapper().selectById(likesCount.getCommentId());
        try {
            redisCache.opsForValue().set(key2,mapper.writeValueAsString(passageComment2));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return ResponseResult.okResult(WebHttpCodeEnum.SUCCESS);
    }

    /**
     * 点赞
     * @param likeCountDto
     * @return
     */
    @Override
    public ResponseResult likesComment(LikeCountDto likeCountDto) {
        log.info("likeCountDto:{}",likeCountDto);
        Integer id = Integer.valueOf(IdsUtils.creatCode());
        LikesCount like = new LikesCount(id,likeCountDto.getUseId(), likeCountDto.getCommentId());
        log.info("like:{}",like);
        int count = likesCountMapper.insert(like);
        if(count<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL);
        String json = null;
        try {
            json = mapper.writeValueAsString(like);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        redisCache.opsForValue().set(RedisCodeEnum.PASSAGE_COMMENT_LIKE.getMsg()+id,json);
        //更新评论的点赞数
        PassageComment passageComment = getBaseMapper().selectById(likeCountDto.getCommentId());
        passageComment.setLikesCount(passageComment.getLikesCount()+1);
        int count2 = getBaseMapper().updateById(passageComment);
        if(count2<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"更新评论点赞数失败");
        //更新redis中的点赞数
        String key2 = RedisCodeEnum.PASSAGE_COMMENT.getMsg()+likeCountDto.getCommentId();
        PassageComment passageComment2 = getBaseMapper().selectById(likeCountDto.getCommentId());
        try {
            redisCache.opsForValue().set(key2,mapper.writeValueAsString(passageComment2));
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return ResponseResult.okResult(WebHttpCodeEnum.SUCCESS);
    }

    /**
     * 获取评论列表
     * @param commentDto
     * @return
     */
    @Override
    public ResponseResult getComments(CommentDto commentDto) {
       
        switch (commentDto.getType()){
            case PassageEnum.LATEST:
                return getLatestComment(commentDto.getPage(),commentDto.getPageSize(),commentDto.getPassageId());
            case PassageEnum.HOT:
                return getHotComment(commentDto.getPage(),commentDto.getPageSize(),commentDto.getPassageId());
            default:
                return ResponseResult.errorResult(WebHttpCodeEnum.FAIL,"没有该选项");
        }
    }

    /**
     * 获取最热评论
     * @param page
     * @param pageSize
     * @return
     */
    private ResponseResult getHotComment(int page, int pageSize,int passageId) {
        //获取所有评论
        List<PassageComment> comments = getBaseMapper().selectByPassageIdOrderByLikesCountDesc(passageId);
        if(comments.size()<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"没有评论");
        //排序
        String phone =  request.getHeader("phone");
        log.info("当前用户的手机号码为:"+phone);
        if(phone!=null) {
            log.info("当前用户的手机号码为:"+phone);
            User user =(User) userClient.getUserByPhone(phone).getData();
            Integer userId = user.getPkId();
            if(userId!=null) {
                comments = sortComments(comments, userId);
            }
        }
        //分页
        int start = (page-1)*pageSize;
        int end = Math.min(start + pageSize, comments.size());
        List<PassageComment> subList = comments.subList(start, end);
        if(subList.size()<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"没有评论");
        List<CommentDtoList> commentDtoLists = convertPassageCommentsToDtoList(subList);
        //组装返回数据
        ResponseResult result = ResponseResult.okResult(200,"获取成功");
        result.setData(commentDtoLists);
        return result;
    }

    /**
     * 获取最新评论
     * @param page
     * @param pageSize
     * @return
     */
    private ResponseResult getLatestComment(int page, int pageSize,int passageId) {
        //获取所有评论
        List<PassageComment> comments = getBaseMapper().selectByPassageIdOrderByTime(passageId);
        log.info("comments:{}",comments);
        if(comments.size()<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"没有评论");
        //排序
        String phone =  request.getHeader("phone");
//        String phone = "19574422385";
        if(phone!=null){
            log.info("当前用户的手机号码为:"+phone);
            User user =(User) userClient.getUserByPhone(phone).getData();
            Integer userId = user.getPkId();
            if(userId!=null) {
                comments = sortComments(comments, userId);
            }
        }
        //分页
        int start = (page-1)*pageSize;
        int end = Math.min(start + pageSize, comments.size());
        List<PassageComment> subList = comments.subList(start, end);
        if(subList.size()<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"没有评论");
        //组装返回数据
        List<CommentDtoList> commentDtoLists = convertPassageCommentsToDtoList(subList);
        if(commentDtoLists.size()<=0)
            return ResponseResult.errorResult(WebHttpCodeEnum.DATA_NOT_EXIST,"没有评论");

        //组装返回数据
        ResponseResult result = ResponseResult.okResult(200,"获取成功");
        result.setData(commentDtoLists);
        return result;
    }

    /**
     * 将自己的评论放在最前面
     * @param comments
     * @param userId
     */
    private List<PassageComment> sortComments(List<PassageComment> comments, int userId) {
        // 自定义比较器，将作者ID与给定用户ID相同的评论排在前面，按照时间从新到旧排序
        Comparator<PassageComment> comparator = new Comparator<PassageComment>() {
            @Override
            public int compare(PassageComment c1, PassageComment c2) {
                // 首先比较是否为给定用户的评论
                boolean isUserComment1 = c1.getAuthorId() == userId;
                boolean isUserComment2 = c2.getAuthorId() == userId;

                // 若两条评论都是给定用户的评论，则按照时间从新到旧排序
                if (isUserComment1 && isUserComment2) {
                    return c2.getPublishTime().compareTo(c1.getPublishTime());
                } else if (isUserComment1) {
                    // 给定用户的评论放在前面
                    return -1;
                } else if (isUserComment2) {
                    // 给定用户的评论放在前面
                    return 1;
                } else {
                    // 其他情况按照时间从新到旧排序
                    return c2.getPublishTime().compareTo(c1.getPublishTime());
                }
            }
        };

        // 使用自定义比较器对评论列表进行排序
        Collections.sort(comments, comparator);
        return comments;
    }

    private List<CommentDtoList> convert(List<CommentDtoList> commentDtoLists){

        List<CommentDtoList> result = new ArrayList<>();
       for (CommentDtoList commentDto : commentDtoLists){
           ReplyDto replyDto = new ReplyDto();
           ArrayList<CommentDtoList> replyList = new ArrayList<>();
           int sum = 0;
           for (CommentDtoList commentDto2 : commentDtoLists){
               log.info(commentDto.toString());
               log.info(commentDto2.toString());
               if(commentDto2.getFatherId().equals(commentDto.getPassageId())&&!commentDto.equals(commentDto2)){
                  sum++;
                  replyList.add(commentDto2);
                  commentDtoLists.remove(commentDto2);
               }
           }
           replyDto.setList(replyList);
           replyDto.setNum(sum);
           commentDto.setReply(replyDto);
           result.add(commentDto);
       }
       return result;
    }

    private CommentDtoList convertToDto(PassageComment passageComment) {
        CommentDtoList commentDto = new CommentDtoList();
        commentDto.setPassageId(String.valueOf(passageComment.getPassageId()));
        commentDto.setFatherId(String.valueOf(passageComment.getParentId()));
        commentDto.setContent(passageComment.getContext());

        // 设置评论者信息
        UserDto commentator = new UserDto(passageComment.getAuthorName(),passageComment.getAuthorAvatar());
        commentDto.setCommentator(commentator);
        return commentDto;
    }
    private List<CommentDtoList> convertPassageCommentsToDtoList(List<PassageComment> passageComments) {
        List<CommentDtoList> commentDtoList = new ArrayList<>();
        for (PassageComment passageComment : passageComments) {
            log.info(passageComment.toString());
            CommentDtoList commentDto = convertToDto(passageComment);
            log.info(commentDto.toString());
            commentDtoList.add(commentDto);
        }
        commentDtoList=convert(commentDtoList);
        return commentDtoList;
    }
}
